/** 
  Copyright (c) 2008, 2009 Claudio Imbrenda
  This program is released under the terms of the
  GNU GPL version 3 or later.
*/
package interfaccia;

import javax.swing.event.*;
import macchina.*;
import javax.swing.*;
import javax.swing.table.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.event.ListDataEvent;

/**
 *
 * @author  Claudio Imbrenda
 */
public class MRConfigurationPanel extends javax.swing.JPanel {
  
    
    private static ResourceBundle bundle_interfaccia = 
          ResourceBundle.getBundle("interfaccia/Bundle_interfaccia");  

  /**
   * The instance of Macchina to be handled.
   */
  private Macchina m;
  
  /**
   * The name of the configuration being displayed.
   */
  private String curc;
  
  private static final String ISTR =bundle_interfaccia.getString("Istruzione");
  private static final String OPCODE=bundle_interfaccia.getString("Opcode");
  
  /** Creates new form MRConfigurationPanel
   * @param mm the instance of Macchina to be handled.
   */
  public MRConfigurationPanel(Macchina mm) {
    m=mm;
    
    initComponents();
    
    tblCurConf.setModel(new TableModel() {

            public int getRowCount() {return 8;}

            public int getColumnCount() {return 8;}

            public String getColumnName(int i) {
                return ((i&1)==0?OPCODE+" (":ISTR+" (")+((i&~1)<<2)+")";
            }

            public Class<?> getColumnClass(int columnIndex) {
                if((columnIndex&1)==0)
                    return Integer.class;
                else
                    return String.class;
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return (columnIndex&1)==1;
            }

            public Object getValueAt(int r, int c) {
                String[] cu = m.getConfiguration(curc);
                try{
                  return (c&1)==0?r+((c&~1)<<2):cu[r+((c&~1)<<2)];
                }catch(IndexOutOfBoundsException ignore){return "###ERR###";}
            }

            public void setValueAt(Object aValue,int rowIndex,int columnIndex){
                if((columnIndex&1)==0)return;
                int inum = rowIndex+((columnIndex/2)*8);
                if(!(aValue instanceof String))
                  return;
                try{
                  m.alterConfiguration((String)comboCurConf.getSelectedItem(),
                          inum, (String)aValue);
                }catch(ClassCastException e){}
            }

            private List<TableModelListener> tllist = 
                    new ArrayList<TableModelListener>();
            private ActionListener macl;
            
            public void addTableModelListener(TableModelListener l) {
                final TableModel t = this;
                if(tllist.size()==0)
                    m.addActionListener(macl=new ActionListener() {
                        public void actionPerformed(ActionEvent e) {
                            switch(e.getID()){
                                case Macchina.INSTRUCTION_SET_CHANGED:
                                case Macchina.CONFIGURATION_SET_CHANGED:
                                case Macchina.EVENT_STATE_HALTED:
                                case Macchina.EVENT_STATE_RUNNING:
                                    for(TableModelListener l:tllist){
                                        l.tableChanged(new TableModelEvent(t));
                                    }
                                    break;
                                default:
                            }
                                
                        }
                    });
                
                tllist.add(l);
            }

            public void removeTableModelListener(TableModelListener l) {
                tllist.remove(l);
                if(tllist.size()==0)
                    m.removeActionListener(macl);
            }  
        });
    
    
    comboCurConf.setModel(new ComboBoxModel() {
      private String sele=null;
      private List<ListDataListener> li = new ArrayList<ListDataListener>();
      private ActionListener al=null;
      public void setSelectedItem(Object anItem) {
        try{
          Object o = m.getConfiguration((String)anItem);
          if(o!=null)sele=(String)anItem;
        }catch(ClassCastException e){
          sele=null;
        }
        fireChange();
      }
      private void fireChange(){
        for(ListDataListener ll:li){
          ll.contentsChanged(new ListDataEvent(
                      this, ListDataEvent.CONTENTS_CHANGED , 0, getSize()));
        }
      }
      public Object getSelectedItem() {
        return sele;
      }
      public int getSize() {
        return m.getConfigurations().length;
      }
      public Object getElementAt(int index) {
        return m.getConfigurations()[index];
      }
      public void addListDataListener(ListDataListener l) {
        if(l==null)return;
        li.add(l);
        if(li.size()==1)
          m.addActionListener(al=new ActionListener() {
            public void actionPerformed(ActionEvent e) {
             if(e.getID()==Macchina.CONFIGURATION_SET_CHANGED)
               fireChange();
            }
          });
      }
      public void removeListDataListener(ListDataListener l) {
        li.remove(l);
        if(li.size()==0)m.removeActionListener(al);
      }
    });
    
    
    
    JComboBox ed = new JComboBox(new ComboBoxModel() {
      private String sele=null;
      private List<ListDataListener> li = new ArrayList<ListDataListener>();
      private ActionListener al=null;
      public void setSelectedItem(Object anItem) {
        //System.out.println("ComboBoxModel.setSelectedItem("+anItem+")");
        try{
          Object o = m.getInstructionCode(((String)anItem).toLowerCase());
          if(o!=null)sele=(String)anItem;
          //fireChange();
          return;
        }catch(ClassCastException e){e.printStackTrace();}
        catch(NullPointerException e){e.printStackTrace();}
        sele=null;
        //fireChange();
      }
      private void fireChange(){
        for(ListDataListener ll:li){
          ll.contentsChanged(new ListDataEvent(
                      this, ListDataEvent.CONTENTS_CHANGED , 0, getSize()));
        }
      }
      public Object getSelectedItem() {
        return sele;
      }
      public int getSize() {
        return m.getInstructions().length;
      }
      public Object getElementAt(int index) {
        return m.getInstructions()[index].toLowerCase();
      }
      public void addListDataListener(ListDataListener l) {
        if(l==null)return;
        li.add(l);
        if(li.size()==1)
          m.addActionListener(al=new ActionListener() {
            public void actionPerformed(ActionEvent e) {
             if(e.getID()==Macchina.INSTRUCTION_SET_CHANGED)
               fireChange();
            }
          });
      }
      public void removeListDataListener(ListDataListener l) {
        li.remove(l);
        if(li.size()==0)m.removeActionListener(al);
      }
    });
    
    DefaultCellEditor de=new DefaultCellEditor(ed);
    
    for(int cx=0;cx<32;cx+=8){
      TableColumn tc = tblCurConf.getColumn(ISTR+" ("+cx+")");
      tc.setCellEditor(de);
      
      tc= tblCurConf.getColumn(OPCODE+" ("+cx+")");
      tc.setPreferredWidth(tc.getPreferredWidth()>>2);
    }
    
    de.setClickCountToStart(2);
    
    comboCurConf.setSelectedItem(m.getCurrentConfiguration());
    curc=m.getCurrentConfiguration();
    
    m.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                switch(e.getID()){
                    case Macchina.CURRENT_CONFIGURATION_CHANGED:
                    case Macchina.EVENT_STATE_HALTED:
                    case Macchina.EVENT_STATE_RUNNING:
                        comboCurConfActionPerformed(e);
                        break;
                    default:
                }
            }
        });
  }
  
  /** This method is called from within the constructor to
   * initialize the form.
   * WARNING: Do NOT modify this code. The content of this method is
   * always regenerated by the Form Editor.
   */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jPanel1 = new javax.swing.JPanel();
        btnNewConf = new javax.swing.JButton();
        jLabel3 = new javax.swing.JLabel();
        jLabel1 = new javax.swing.JLabel();
        comboCurConf = new javax.swing.JComboBox();
        jLabel2 = new javax.swing.JLabel();
        jButton1 = new javax.swing.JButton();
        jLabel4 = new javax.swing.JLabel();
        btnUseConf = new javax.swing.JButton();
        jPanel2 = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        tblCurConf = new javax.swing.JTable();

        setLayout(new java.awt.BorderLayout());

        jPanel1.setLayout(new javax.swing.BoxLayout(jPanel1, javax.swing.BoxLayout.X_AXIS));

        btnNewConf.setText(bundle_interfaccia.getString("Nuova...")); // NOI18N
        btnNewConf.setToolTipText(bundle_interfaccia.getString("Aggiungi_nuova_configurazione...")); // NOI18N
        btnNewConf.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnNewConfActionPerformed(evt);
            }
        });
        jPanel1.add(btnNewConf);

        jLabel3.setText("   ");
        jPanel1.add(jLabel3);

        jLabel1.setLabelFor(comboCurConf);
        jLabel1.setText(bundle_interfaccia.getString("Configurazione:_")); // NOI18N
        jPanel1.add(jLabel1);

        comboCurConf.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        comboCurConf.setToolTipText(bundle_interfaccia.getString("Configurazione_corrente")); // NOI18N
        comboCurConf.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                comboCurConfActionPerformed(evt);
            }
        });
        jPanel1.add(comboCurConf);

        jLabel2.setText("  ");
        jPanel1.add(jLabel2);

        jButton1.setText(bundle_interfaccia.getString("Elimina")); // NOI18N
        jButton1.setToolTipText(bundle_interfaccia.getString("Elimina_configurazione_corrente")); // NOI18N
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });
        jPanel1.add(jButton1);

        jLabel4.setText("  ");
        jPanel1.add(jLabel4);

        btnUseConf.setText(bundle_interfaccia.getString("Usa")); // NOI18N
        btnUseConf.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnUseConfActionPerformed(evt);
            }
        });
        jPanel1.add(btnUseConf);

        add(jPanel1, java.awt.BorderLayout.NORTH);

        jPanel2.setLayout(new java.awt.BorderLayout());

        tblCurConf.setRowHeight(22);
        tblCurConf.setRowSelectionAllowed(false);
        tblCurConf.getTableHeader().setReorderingAllowed(false);
        jScrollPane1.setViewportView(tblCurConf);

        jPanel2.add(jScrollPane1, java.awt.BorderLayout.CENTER);

        add(jPanel2, java.awt.BorderLayout.CENTER);
    }// </editor-fold>//GEN-END:initComponents

  private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
    String s= comboCurConf.getSelectedItem().toString().toLowerCase();
    String[] tc = m.getConfigurations();
    if(tc.length==1)return;
    
    String delenda = tc[0].toLowerCase().equals(s)?tc[1]:tc[0];
    
    String oldc = curc;
    curc=delenda;
    
    if(m.removeConfiguration(s))
        comboCurConf.setSelectedItem(delenda);
    else
        curc=oldc;
  
  }//GEN-LAST:event_jButton1ActionPerformed

  private void comboCurConfActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_comboCurConfActionPerformed
    try{
      curc=(String)comboCurConf.getSelectedItem();
    }catch(ClassCastException e){}
    if(curc==null)return;
    jButton1.setEnabled(m.isRemovableConf(curc));
    tblCurConf.setEnabled(m.isAlterableConf(curc));
    tblCurConf.repaint();
}//GEN-LAST:event_comboCurConfActionPerformed


  /**
   * The default configuration: all NOPs.
   */
  String[] vuota= {
    "nop","nop","nop","nop","nop","nop","nop","nop",
    "nop","nop","nop","nop","nop","nop","nop","nop",
    "nop","nop","nop","nop","nop","nop","nop","nop",
    "nop","nop","nop","nop","nop","nop","nop","nop"
  };
  
  private void btnNewConfActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnNewConfActionPerformed
    String res=JOptionPane.showInputDialog(
            bundle_interfaccia.getString("Inserire_il_nome_della_nuova_configurazione:"),"");
    if(res==null)return;
    m.addConfiguration(res, vuota);
    res=res.toLowerCase();
    comboCurConf.setSelectedItem(res);
}//GEN-LAST:event_btnNewConfActionPerformed

  private void btnUseConfActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnUseConfActionPerformed
    m.setConfiguration(curc);
}//GEN-LAST:event_btnUseConfActionPerformed
  
  
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnNewConf;
    private javax.swing.JButton btnUseConf;
    private javax.swing.JComboBox comboCurConf;
    private javax.swing.JButton jButton1;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable tblCurConf;
    // End of variables declaration//GEN-END:variables
  
}
